#include "YSysWatchDog.h"

#include <QSettings>
#include <QDebug>
#include <iostream>
#include <QTime>
using namespace std;
YSysWatchDog::YSysWatchDog(QObject *parent) :
    QThread (parent)
{
    m_pUdpSocket = 0;
}

bool YSysWatchDog::init(const QString &confPath)
{
    QSettings settings(confPath,QSettings::IniFormat);
    if(settings.allKeys().size()<=0)
    {
        cout<< "加载"<< confPath.toLocal8Bit().data() <<"配置文件失败" <<endl;
        return false;
    }


    settings.setIniCodec("GB2312"); //在此添加设置，即可读写ini文件中的中文
    m_strLocalIp = settings.value("WatchDog/LocalIp").toString();
    m_strGroupIp = settings.value("UDP Multicast/IP").toString();
    m_usGroupPort = settings.value("UDP Multicast/Port").toUInt();


    return true;

}

int YSysWatchDog::initUdpGroup()
{
    {
        cout << "Start to create network ,local ip:"<< m_strLocalIp.toLocal8Bit().data() <<
                " group ip: " << m_strGroupIp.toLocal8Bit().data() <<
                " group prot:"<< m_usGroupPort<<"..." << endl;
        m_pUdpSocket = new QUdpSocket(this);
        //m_pUdpSocket->moveToThread(this);
        QHostAddress addr(m_strLocalIp);
        QHostAddress groupAddress(m_strGroupIp);
        cout << "bind IP..." << endl;
        if(!m_pUdpSocket->bind(QHostAddress::AnyIPv4, m_usGroupPort,QAbstractSocket::ReuseAddressHint|QAbstractSocket::ShareAddress))
        {
            QString strContent = "bind IP:"+m_strLocalIp+" failure,"+m_pUdpSocket->errorString();
            /*onLatestNews(DOG_TYPE_LinkError,
                         m_strGroupIp.toLocal8Bit().data(),
                         strContent.toLocal8Bit().data(),strContent.toLocal8Bit().length());*/
            return m_pUdpSocket->error();
        }
        cout << "joinMulticastGroup..." << endl;

        if(!m_pUdpSocket->joinMulticastGroup(groupAddress))
        {

            QString strContent = "create network failure:"+m_pUdpSocket->errorString();
            /* onLatestNews(DOG_TYPE_LinkError,
                         m_strGroupIp.toLocal8Bit().data(),
                         strContent.toLocal8Bit().data(),strContent.toLocal8Bit().length());*/
            return m_pUdpSocket->error();
        }
#ifdef QT_NO_DEBUG
        cout << "Does not accept local port data!" << endl;
        m_pUdpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0);//禁止接收本地端口数据
#endif
        //cout << "Load reading signal..." << endl;
        //connect(m_pUdpSocket, SIGNAL(readyRead()),this, SLOT(readPendingDatagrams()));
        cout << "The multicast network was created successfully!" << endl;
        sendInit();
        return 0;
    }
}
void YSysWatchDog::readPendingDatagrams()
{
    while (m_pUdpSocket->hasPendingDatagrams())
    {

        QByteArray datagram;
        datagram.resize(m_pUdpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        m_pUdpSocket->readDatagram(datagram.data(), datagram.size(),
                                   &sender, &senderPort);

        if(processDatagram(datagram))
        {
            ;
        }
    }
}

void YSysWatchDog::run()
{
    if(m_pUdpSocket == 0)
        initUdpGroup();
    QTime timer;
    timer.start();
    while(1)
    {

        if(m_pUdpSocket->waitForReadyRead(1000))
        {

            readPendingDatagrams();

        }
        if(timer.elapsed()>=1000)
        {
            onTimeout();
            timer.restart();
        }

    }

}
bool YSysWatchDog::processDatagram(QByteArray data)
{
    const int headSize = sizeof(_tagWatchDog);
    const QHostAddress localAddr(m_strLocalIp);

    if(!data.isNull())
    {
        _tagWatchDog dog;
        if(data.length()<headSize)
        {
            return false;
        }
        memset(&dog,0,headSize);
        memcpy(&dog,data.data(),headSize);
        if(dog.usStart != DOGHEADSTART || dog.usEnd != DOGHEADEND)
        {
            return false;
        }
        QHostAddress srcAddr(dog.srcIp);
        if(localAddr == srcAddr)
        {
            return false;
        }

        onLatestNews(dog);
        return true;

    }
    return false;
}

void YSysWatchDog::onShakeHands(int num)
{
    qDebug() << num;
}
void YSysWatchDog::onLatestNews(_tagWatchDog dog)
{
    switch (dog.type) {
    case DOG_TYPE_Init:
    case DOG_TYPE_ShakeHand:
        m_mapSession[dog.srcIp] = 0;
        break;
    case DOG_TYPE_Restart:
        if(dog.destIp == m_strLocalIp)
        {
            m_funRestart();
            emit restart();
        }
        break;
    default:
        break;
    }
}
void YSysWatchDog::onTimeout()
{
    QMap<QString,int>::iterator itSession = m_mapSession.begin();
    sendShakeHands();
    for(;itSession != m_mapSession.end();itSession++)
    {
        itSession.value()++;
    }
}
void YSysWatchDog::getSessionList()
{
    if(m_mapSession.size() <= 0)
    {
        cout << "session count :" << m_mapSession.size()<<endl;
        return ;
    }
    QMap<QString,int>::iterator itSession = m_mapSession.begin();
    int nNum = itSession.value();
    const char * pVal = 0;
    cout << "\tIP" << "\ttype" << endl;
    for(;itSession != m_mapSession.end();itSession++)
    {
        pVal = nNum >= 3 ? "Offline":"online";
        cout << itSession.key().toLocal8Bit().data() <<"\t"<< pVal <<endl;
    }
}
int YSysWatchDog::sendInit()
{
    return write(0,0,"",DOG_TYPE_Init);
}

int YSysWatchDog::sendRestart(const char *pIp)
{
    write(0,0,pIp,DOG_TYPE_Restart);
}

void YSysWatchDog::setRestartFun(RestartFun pRestart)
{
    m_funRestart = pRestart;
}
int YSysWatchDog::sendShakeHands()
{
    return write(0,0,"",DOG_TYPE_ShakeHand);
}
qint64 YSysWatchDog::write(const char *data, qint64 len,QString destIp,_tagWatchDogType type)
{

    const int headSize = sizeof(_tagWatchDog);
    QHostAddress addr(m_strGroupIp);
    _tagWatchDog dog;
    memset(&dog,0,headSize);
    dog.usStart = DOGHEADSTART;
    dog.usEnd = DOGHEADEND;
    dog.type  = type;
    memcpy(dog.destIp,destIp.toLocal8Bit().data(),
           destIp.toLocal8Bit().length());
    memcpy(dog.srcIp,m_strLocalIp.toLocal8Bit().data(),m_strLocalIp.length());

    dog.size = headSize + len;
    QByteArray sendByte;
    sendByte.append((char*)&dog,headSize);
    sendByte.append(data,len);
    int res = m_pUdpSocket->writeDatagram(sendByte.data(),sendByte.length(),addr,m_usGroupPort);

    //cout << "To send data length:" << res <<endl;
    return res;
}
